#coding=utf-8
'''
Created on 2015年5月27日
'''

from util_base.exception import UFOException, ParamException
from util_base.protocol import ResponseBuilder
from protobuf_base import protobuf, common_pb2
from protobuf_to_dict import protobuf_to_dict, dict_to_protobuf
from common_base.errors import AliveError
from handler_base.base_handler import BaseHandler
from util_base.common_decorators import override
import json
from util_base.logging_utils import Tracker
from common_base.constants import LanguageType
import base64
import hashlib



class MainHandler(BaseHandler):
    '''
    main handler, receive requests and distribute them to processors
    '''
    
    def __init__(self, *request, **kwargs):
        '''
        Constructor
        '''
        
        super(MainHandler, self).__init__(request[0], request[1])
        self.set_header("Content-Type", "application/octet-stream")
        self.tracker = Tracker('track')
        self.sys_logger = Tracker('root')
        self.db_pool = set()
        
    @override
    def parse_header(self):
        '''
        解析请求头
        '''
        
        # 从header中解析参数
        
        try:
            self.cmdid = int(self.request.headers.get('Cmdid'))
        except:
            raise ParamException('Cmdid')
        
        try:
            self.app_id = self.request.headers.get('AppID')
        except:
            raise ParamException('AppID')
         
        try: 
            self.timestamp = int(self.request.headers.get('Timestamp'))
        except:
            raise ParamException('Timestamp') 
        
        try: 
            self.nonce_str = self.request.headers.get('NonceStr')
        except:
            raise ParamException('NonceStr') 
        
        try: 
            self.sign_type = self.request.headers.get('SignType')
        except:
            raise ParamException('SignType') 
        
        try: 
            self.request_sign = self.request.headers.get('RequestSign')
        except:
            raise ParamException('RequestSign') 
        
        
        # 校验签名  数据库查询
        if 23001 <= self.cmdid < 23500 :
                    # 校验签名
            secretKey = self.application.dapp_info.get(self.app_id, '')
            sign_str = '''AppID=%s&Body=%s&NonceStr=%s&SignType=%s&Timestamp=%s&secretKey=%s'''%(self.app_id,base64.b64encode(self.request.body).decode('utf-8'), self.nonce_str,
                                                                self.sign_type, self.timestamp, secretKey)
            if self.sign_type.upper() != "MD5":
                raise ParamException('SignType') 
            else:
                if  hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper() != self.request_sign:
                    raise ParamException('RequestSign') 
        

        # SDK
        elif  23501 <= self.cmdid < 23900:
            pass
            # dapp = self._get_dapp_info()
            # if dapp:
            #     secretKey = dapp['secret_key']
            #     sign_str = '''AppID=%s&Body=%s&NonceStr=%s&SignType=%s&Timestamp=%s&secretKey=%s'''%(self.app_id,base64.b64encode(self.request.body).decode('utf-8'), self.nonce_str,
            #                                                         self.sign_type, self.timestamp, secretKey)
            #     if self.sign_type.upper() != "MD5":
            #         raise ParamException('SignType')
            #     else:
            #         if  hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper() != self.request_sign:
            #             raise ParamException('RequestSign')
            # else:
            #     raise ParamException('AppID')
        else:
            raise ParamException('CMDID')
        
    # def _get_dapp_info(self):
    #     res = []
    #     try:
    #         sdk_db = self._get_db(TTCSDKCDB)
    #         res = sdk_db.query("""select secret_key from dapp where uuid='%s' """%self.app_id)
    #     except:
    #         raise
    #     finally:
    #         self._return_connections()
    #     return res[0] if res else {}
            
    def _get_db(self, db_cls):
        '''
        mysql连接
        '''
        
        rp, wp = self.application.db_conns['%s_read' % (db_cls.database)], self.application.db_conns['%s_write' % (db_cls.database)]
        
        if getattr(self.application, 'use_pooled_db', True):
            rc, wc = rp.get_connection(), wp.get_connection()
            db = db_cls(rc, wc)
            self.db_pool.add((rp, rc))
            self.db_pool.add((wp, wc))
            
            return db
        else:
            return db_cls(rp, wp)
    
    def _return_connections(self):
        '''
        '''
        
        for pool, conn in self.db_pool:
            pool.return_connection(conn)
            
        self.db_pool = set()
    
    @override
    def parse_body(self):
        '''
        解析请求体
        '''
        
        # protobuf解析 
        json_body = self._deserialize_body()
        # TODO: 过滤非法字符
        
        # 参数校验
        if 'common' not in json_body:
            raise ParamException('common')
        common = json_body.get('common')
        self.common = common

        if 'userId' not in common:
            raise ParamException('userId')
        self.userid = common.get('userId')
        
        
#         if 'cmdId' not in common:
#             raise ParamException('cmdId')
#         self.cmdid = common.get('cmdId')
        
        if 'release' in common:
            self.release = common.get('release')
        if 'platform' in common:
            self.platform = common.get('platform')
        

        # 没有指定语言默认为中文
        self.language = common.get('language', LanguageType.CN)

        if 'params' in json_body:
            self.params = json_body.get('params')

        return json_body
    
    
     
    @override
    def verify_processor_meta(self, meta):
        '''
        processor_meta校验
        '''
        
        if meta.internal_only:
            # 内部调用的协议
            raise UFOException(AliveError.ERROR_COMMON_PROTOCOL_FOR_INTERNAL_ONLY)
        
    @override
    def serialize_response(self):
        '''
        '''
        
        res_cls = common_pb2.Response
        try:
            # 根据cmdid反射protobuf解析类
            if (hasattr(protobuf, 'Response%s'% self.cmdid)):
                res_cls = getattr(protobuf, 'Response%s'% self.cmdid)
            return dict_to_protobuf(res_cls, self.res).SerializeToString()
        except:
            self.tracker.trace_error()
            self.tracker.error(json.dumps(self.res), 'OriginReponseMsg')
            self.res = ResponseBuilder.build_error(self, UFOException(AliveError.ERROR_COMMON_PROTOBUF_SERIALIZE_FAILED))
            return dict_to_protobuf(res_cls, self.res).SerializeToString()
    
    def _deserialize_body(self):
        '''
        反序列化为json
        '''

        # 根据cmdid反射protobuf解析类
        if not hasattr(protobuf, 'Request%s'% self.cmdid):
            raise UFOException(AliveError.ERROR_COMMON_UNIMPLEMENT_PROTOBUF)
        try:
            # 解析protobuf
            body = getattr(protobuf, 'Request%s'% self.cmdid)()
            body.ParseFromString(self.request.body)
        except:
            raise UFOException(AliveError.ERROR_COMMON_PARSE_PROTOBUF_FAILED)
        
        return protobuf_to_dict(body)
